#pragma once
#include "abstract.hpp"
#include "files.hpp"
#include "message.hpp"
#include "net.hpp"
#include <functional>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <unordered_map>

namespace rpc
{
    class CallBack
    {
    public:
        using ptr = std::shared_ptr<CallBack>;
        CallBack()
        {}
        virtual void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) = 0;
    };

    template<typename  T>
    class CallBackT : public CallBack
    {
    public:
        using ptr = std::shared_ptr<CallBackT<T>>;
        using MessageCallBack = std::function<void(const BaseConnection::ptr& conn, std::shared_ptr<T> &msg)>;
        CallBackT(const MessageCallBack &handler):_handler(handler)
        {}
        void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) override
        {
            //现在msg类型是传入的T了
            auto type_msg = std::dynamic_pointer_cast<T>(msg);
            _handler(conn, type_msg);
        }
    private:
        MessageCallBack _handler;
    };

    class DisPatcher
    {
    public:
        using ptr = std::shared_ptr<DisPatcher>;

        template<typename  T>
        void registerHandler(MType mtype, const typename CallBackT<T>::MessageCallBack &handler)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto cb = std::make_shared<CallBackT<T>>(handler);
            _handlers.insert({mtype, cb});
        }

        //调用对应映射的函数 
        void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _handlers.find(msg->mtype());
            if(it != _handlers.end())
            {
                //找到了消息类型对应的业务处理函数，进行调用
                it->second->onMessage(conn, msg);
            }
            else 
            {
                ELOG("收到未知类型消息！");
                conn->shutdown();
            }
        }
    private:
        std::mutex _mutex;
        std::unordered_map<MType, CallBack::ptr> _handlers;
    };
}